import { Injectable } from '@nestjs/common';
import Axios from 'axios';
import { createHash } from 'crypto';
import { writeFileSync, readFileSync, constants, accessSync, mkdirSync, unlinkSync } from 'fs';
import { join } from 'path'
import { AuthService } from 'src/auth/auth.service';
import { Bk_User } from 'src/users/bk_user.entity';
import { UsersService } from 'src/users/users.service';
import { UtilsService } from 'src/utils/utils.service';

const wxApiAxios = Axios.create(
    {
        baseURL: 'https://api.weixin.qq.com/',
    }
)
wxApiAxios.interceptors.response.use((response) => {
    if (response.data.errcode == 40001) {
        console.log(response);
    }
    return response
})

@Injectable()
export class WechatService {
    constructor(
        private readonly usersServices: UsersService
    ) {
        console.log('启动刷新accesstoken')
        this.refreshAccessToken()
    }
    accessTokenTimer: string | number | NodeJS.Timeout;
    // 使用code 换取用户accesstoken
    async getOpenId(query: any, authService: AuthService) {
        const { data } = await wxApiAxios.get(`/sns/jscode2session`, {
            params: {
                appid: 'wxdc5881a7a5462f77',
                secret: '3ac4be37a5ab66ddcfff9afb0df61ca3',
                js_code: query.code,
                grant_type: 'authorization_code'
            }
        });
        const { openid, unionid } = data;
        const user = await this.usersServices.findOneByUnionId(unionid);
        let phone: string;
        phone = user ? user.phone : "";
        return {
            openid,
            unionid,
            phone,
            token: (await authService.createOrUpdateUser(unionid)).access_token
        };
    }
    // 前端调起扫描微信公众号二维码登陆接口，返回 二维码
    async qrCodeLogin(
        scene_str: string
    ) {
        const accessToken = this.getAccessToken('wx_access_token');
        const result = await wxApiAxios.post('/cgi-bin/qrcode/create', {
            expire_seconds: 3600,
            action_name: 'QR_STR_SCENE',
            action_info: {
                scene: {
                    scene_str
                }
            }
        }, {
            params: {
                access_token: accessToken
            }
        });
        return result.data;
    }
    //  创建微信 jssdk ticket
    async createJsapiTicket(access_token: string) {
        if (!access_token) {
            access_token = this.getAccessToken('wx_access_token');
        }
        const reslut = await wxApiAxios.get(`/cgi-bin/ticket/getticket`, {
            params: {
                access_token,
                type: 'jsapi'
            }
        });
        writeFileSync(join(__dirname, '..', 'wx_jsapi_ticket'), reslut.data.ticket);
        return reslut.data.ticket as string;
    }

    getJsapiTicket() {
        return readFileSync(join(__dirname, '..', 'wx_jsapi_ticket')).toString();
    }

    jsapiSignature(url: string, utilsService: UtilsService) {
        const jsapi_ticket = this.getJsapiTicket();
        const noncestr = utilsService.randomString(16);
        const timestamp = parseInt(String(Date.now() / 1000));
        const stringValue = `jsapi_ticket=${jsapi_ticket}&noncestr=${noncestr}&timestamp=${timestamp}&url=${url}`;
        console.log(stringValue);
        const tmpStr = createHash('sha1').update(stringValue).digest('hex');
        console.log(tmpStr);
        return {
            timestamp,
            nonceStr: noncestr,
            signature: tmpStr
        }
    }

    // 刷新 access token
    async refreshAccessToken(isError?: 'error'): Promise<{ expires_in: number; access_token: string; }> {
        if (this.accessTokenTimer) {
            clearTimeout(this.accessTokenTimer);
            this.accessTokenTimer = null;
        }
        let accessToken: { expires_in: number; access_token: string; };
        try {
            accessToken = await this.createAccessToken('wx6b259d01ab855cc5', 'fc28e1315594590a75884cb06e0d969c', 'wx_access_token');//公众号微信后台接口token
            await this.createAccessToken('wxdc5881a7a5462f77', '3ac4be37a5ab66ddcfff9afb0df61ca3', 'wxxcx_access_token');//小程序后台接口token
        } catch (error) {
            accessToken = await this.refreshAccessToken('error');
        }
        if (isError === 'error') {
            return accessToken;
        }
        this.createJsapiTicket(accessToken.access_token);
        this.accessTokenTimer = setTimeout(() => this.refreshAccessToken(), (accessToken.expires_in * 1000) - (10 * 60 * 1000));
        return accessToken;
    }
    // 获取微信的accessToken，保存在本地文件中
    async createAccessToken(appid: string, secret: string, fileName: string) {
        const result = await wxApiAxios.get('/cgi-bin/token', {
            params: {
                grant_type: 'client_credential',
                // appid: 'wx6b259d01ab855cc5',
                // secret: 'fc28e1315594590a75884cb06e0d969c'
                appid,
                secret
            }
        });
        const data = result.data as {
            access_token: string;
            expires_in: number;
        };
        if (!data.access_token) {
            throw new Error('请求失败');
        }

        // writeFileSync(join(__dirname, '..', 'wx_access_token'), result.data.access_token);
        writeFileSync(join(__dirname, '..', fileName), result.data.access_token);
        return result.data as {
            access_token: string;
            expires_in: number;
        };
    }
    // 从已保存 微信accesstoken 在本地的文件中读取 access文件
    getAccessToken(fileName: string) {
        return readFileSync(join(__dirname, '..', fileName)).toString();
    }


    // 获取并保存 微信用户授权 access_token
    async createUserAuthAccessToken(code: string) {
        const result = await wxApiAxios.get(`/sns/oauth2/access_token`, {
            params: {
                appid: 'wx6b259d01ab855cc5',
                secret: 'fc28e1315594590a75884cb06e0d969c',
                code,
                grant_type: 'authorization_code'
            }
        });
        writeFileSync(join(__dirname, 'user_token', 'wx_user_auth_access_token_' + result.data.openid), JSON.stringify(result.data));
        return result.data;
    }
    // 从本地临时文件中获取微信用户授权 access_token
    getUserAuthAccessToken(openid: string) {
        try {
            const access_token = readFileSync(join(__dirname, 'user_token', 'wx_user_auth_access_token_' + openid)).toString();
            return JSON.parse(access_token);
        } catch (error) {
            return null;
        }
    }



    // 查看本地是否存在保存token的临时文件
    userTokenIsHas(name: string) {
        try {
            accessSync(join(__dirname, 'user_token', name), constants.F_OK);
            return true
        } catch (err) {
            return false;
        }
    }
    // 从本地临时文件读取token返回给前端
    getUserToken(name: string) {
        try {
            return readFileSync(join(__dirname, 'user_token', name)).toString();
        } catch (error) {
            return ''
        }
    }
    // 删除保存token的临时文件
    removeUserToken(name: string) {
        return unlinkSync(join(__dirname, 'user_token', name));
    }

    // 将用户token保存到临时文件中等待前端获取
    setUserToken(name: string, token: string) {
        writeFileSync(join(__dirname, 'user_token', name), token);
    }

    async getWechatUserPhoneNumber(query: { avatarUrl: string, nickName: string, unionid: string, code: string }) {
        const access_token = this.getAccessToken('wxxcx_access_token');
        const { nickName: nickname, avatarUrl: headimgurl, unionid, code } = query;
        const { data } = await wxApiAxios.post(`wxa/business/getuserphonenumber?access_token=${access_token}`, {
            code
        });
        const { phoneNumber: phone } = data.phone_info;
        let user = await this.usersServices.findOneByUnionId(unionid);
        if (user) {
            user.headimgurl = headimgurl;
            user.nickname = nickname;
            user.phone = phone;
            await this.usersServices.updateUserinfo(user);
            return user.phone;
        } else {
            const createUser = await this.usersServices.create(unionid, { nickname, headimgurl, phone });
            return createUser ? createUser.phone : null;
        }
    }
}
